package pattern.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import pattern.SmsServiceTool;
import pattern.annontations.Menu;
import pattern.annontations.Secure;
import pattern.config.BaseSmsConfig;
import pattern.exception.AssertTool;
import pattern.platform.SmsPlatform;
import pattern.result.ResponseData;
import pattern.routing.WorkSmsApiRouting;
import pattern.sms.SendSmsModel;
import pattern.sms.TemplateCode;
import pattern.utils.SpringTool;

import java.util.Map;

/**
 * @author Simon
 * @date 2020-08-21
 */
@Api(tags = "短信相关接口")
@ApiSort(3)
@RestController
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Secure
@Slf4j
@RequestMapping(WorkSmsApiRouting.Sms.BASE)
@Menu(menuName = "sms", menuUri = "sms", foundational = false)
public class SmsController {

    private final BaseSmsConfig baseSmsConfig;

    @ApiOperation(value = "发送注册验证码")
    @GetMapping(WorkSmsApiRouting.Sms.SEND_CODE)
    @Secure(value = -1,actionUri = "sms:send", actionName = "send", actionNote = "sms")
    public ResponseData<Boolean> sendCode(String phone) {
        AssertTool.isTrue(phone.length() > 5, "手机号码长度错误");
        //存入缓存
        var code = RandomUtil.randomInt(1000,10000);
        if (baseSmsConfig.getIsMock()) {
            code = 8888;
            //mock环境
            log.info("{}的验证码为：{}", phone, code);
            SmsServiceTool.getMsgCache().code.put(phone, String.valueOf(code));
        } else {
            if (this.check(phone)) {
                return new ResponseData<>(Boolean.FALSE);
            }
            SmsServiceTool.getMsgCache().code.put(phone, String.valueOf(code));
            Map<String, String> map = Maps.newHashMap();
            map.put("code", String.valueOf(code));
            SendSmsModel sendSmsModel = new SendSmsModel();
            sendSmsModel.setPhoneNumbers(phone);
            sendSmsModel.setTemplateCode(TemplateCode.CODE);
            sendSmsModel.setTemplateParam(map);
            SpringTool.getBean(SmsPlatform.getClazz(baseSmsConfig.getPlatform())).send(sendSmsModel);
            SmsServiceTool.getMsgCache().sendTime.put(phone, new DateTime());
        }
        return new ResponseData<>(Boolean.TRUE);
    }

    @ApiOperation(value = "发送登录验证码")
    @GetMapping(WorkSmsApiRouting.Sms.SEND_LOGIN)
    @Secure(value = -1,actionUri = "sms:send", actionName = "send", actionNote = "sms")
    public ResponseData<Boolean> sendLogin(String phone) {
        AssertTool.isTrue(phone.length() > 5, "手机号码长度错误");
        //存入缓存
        var code = RandomUtil.randomInt(1000,10000);
        if (baseSmsConfig.getIsMock()) {
            code = 8888;
            //mock环境
            log.info("{}的验证码为：{}", phone, code);
            SmsServiceTool.getMsgCache().code.put(phone, String.valueOf(code));
        } else {
            if (this.check(phone)) {
                return new ResponseData<>(Boolean.FALSE);
            }
            SmsServiceTool.getMsgCache().code.put(phone, String.valueOf(code));
            Map<String, String> map = Maps.newHashMap();
            map.put("code", String.valueOf(code));
            SendSmsModel sendSmsModel = new SendSmsModel();
            sendSmsModel.setPhoneNumbers(phone);
            sendSmsModel.setTemplateCode(TemplateCode.CODE);
            sendSmsModel.setTemplateParam(map);
            SpringTool.getBean(SmsPlatform.getClazz(baseSmsConfig.getPlatform())).send(sendSmsModel);
            SmsServiceTool.getMsgCache().sendTime.put(phone, new DateTime());
        }
        return new ResponseData<>(Boolean.TRUE);
    }

    @ApiOperation(value = "发送找回密码验证码")
    @GetMapping(WorkSmsApiRouting.Sms.SEND_FIND)
    @Secure(value = -1,actionUri = "sms:send", actionName = "send", actionNote = "sms")
    public ResponseData<Boolean> sendFind(String phone) {
        AssertTool.isTrue(phone.length() > 5, "手机号码长度错误");
        //存入缓存
        var code = RandomUtil.randomInt(1000,10000);
        if (baseSmsConfig.getIsMock()) {
            code = 8888;
            //mock环境
            log.info("{}的验证码为：{}", phone, code);
            SmsServiceTool.getMsgCache().code.put(phone, String.valueOf(code));
        } else {
            if (this.check(phone)) {
                return new ResponseData<>(Boolean.FALSE);
            }
            SmsServiceTool.getMsgCache().code.put(phone, String.valueOf(code));
            Map<String, String> map = Maps.newHashMap();
            map.put("code", String.valueOf(code));
            SendSmsModel sendSmsModel = new SendSmsModel();
            sendSmsModel.setPhoneNumbers(phone);
            sendSmsModel.setTemplateCode(TemplateCode.CODE_FIND);
            sendSmsModel.setTemplateParam(map);
            SpringTool.getBean(SmsPlatform.getClazz(baseSmsConfig.getPlatform())).send(sendSmsModel);
            SmsServiceTool.getMsgCache().sendTime.put(phone, new DateTime());
        }
        return new ResponseData<>(Boolean.TRUE);
    }

    @ApiOperation(value = "验证验证码")
    @GetMapping(WorkSmsApiRouting.Sms.CHECK_CODE)
    @Secure(value = -1)
    public ResponseData<Boolean> checkCode(@RequestParam(value = "type",required = false) String type, @RequestParam("phone") String phone, @RequestParam("code") String code) {
        var data = SmsServiceTool.getMsgCache().code.GET(phone);
        if (data.isSuccess()) {
            if (data.getValue().equals(code)) {
                return new ResponseData<>(Boolean.TRUE);
            }
        }
        return new ResponseData<>(Boolean.FALSE);
    }

    /**
     * 校验30s有无发送短信
     */
    private boolean check(String phone) {
        var data = SmsServiceTool.getMsgCache().sendTime.GET(phone);
        if (data.isSuccess()) {
            var between = DateUtil.between(data.getValue(), new DateTime(), DateUnit.SECOND);
            if (between <= 30L) {
                log.warn("30s内有发送短信无法重新发送{}", phone);
                //小于等于30
                return true;
            }
        }
        return false;
    }
}
